package com.fly_fox.util;

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.google.common.base.Joiner;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;

public class JdbcUtil extends JdbcTemplate {

    public static JdbcUtil ins;

    // 表示定义数据库的用户名
    public static String username ;

    // 定义数据库的密码
    public static String pwd;

    // 定义数据库的驱动信息
    public static String driver;

    // 定义访问数据库的地址
    public static String url;

    // 定义数据库的链接
    private Connection connection;

    /**
     * 加载数据库配置信息，并给相关的属性赋值
     */
    public static void loadConfig(Properties prop) {
        username = prop.getProperty("jdbc.user");
        pwd = prop.getProperty("jdbc.pwd");
        driver = prop.getProperty("jdbc.driver");
        url = prop.getProperty("jdbc.url");
        //  加载数据库
        DruidDataSource dataSource=new DruidDataSource();
        dataSource.setUsername(username);
        dataSource.setPassword(pwd);
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        //  最多存在两个连接
        dataSource.setMaxActive(2);
        dataSource.setMinIdle(0);
        dataSource.setMaxWait(9000);//  9秒连接超时就断开
        ins=new JdbcUtil();
        ins.setDataSource(dataSource);
    }

    /**
     * 加载数据库配置信息，并给相关的属性赋值
     */
    public static void loadConfig(Path path) {

        SafeProperties prop=new SafeProperties();
        try(InputStream is=new FileInputStream(path.toFile())) {
            prop.load(is);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        username = prop.getProperty("jdbc.user");
        pwd = prop.getProperty("jdbc.pwd");
        driver = prop.getProperty("jdbc.driver");
        url = prop.getProperty("jdbc.url");
        //  加载数据库
        DruidDataSource dataSource=new DruidDataSource();
        dataSource.setUsername(username);
        dataSource.setPassword(pwd);
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        //  最多存在两个连接
        dataSource.setMaxActive(2);
        dataSource.setMinIdle(0);
        dataSource.setMaxWait(9000);//  9秒连接超时就断开
        ins=new JdbcUtil();
        ins.setDataSource(dataSource);
    }

    public JdbcUtil() {

    }

    /**
     * 获取数据库连接
     *
     * @return 数据库连接
     */
    public Connection getConnection() {
        try {
            Class.forName(driver); // 注册驱动
            connection = DriverManager.getConnection(url, username, pwd); // 获取连接
        } catch (Exception e) {
            throw new RuntimeException("get connection error!", e);
        }
        return connection;
    }

    /*public static void main(String[] args) {
        JdbcUtil jdbcUtil = new JdbcUtil();
        jdbcUtil.getConnection();
        try {
            List<Map<String, Object>> result = jdbcUtil.findResult(
                    "select * from t_student", null);
            for (Map<String, Object> m : result) {
                System.out.println(m);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            jdbcUtil.releaseConn();
        }
    }*/

    public String toSelSql(Class tbCla, String where){
        String tbName=getTbName(tbCla);

        //  key为数据库列名称 值为字段名称
        Map<String,String> selColMap=new HashMap<>();
        for (Field fd : FieldUtils.getAllFields(tbCla)) {
            String colName=getColName(fd);
            if(colName==null){
                continue;
            }
            String fdName=fd.getName();


            if(StringUtils.isEmpty(colName)){
                colName=StringHelper.camelToUnderline(fdName);
                selColMap.put(colName,fdName);
            }

            //  推送kv
            selColMap.put(colName,fdName);
            
        }

        StringBuilder strBud=new StringBuilder();
        strBud.append("select ");
        String joiner = Joiner.on(",").useForNull("").withKeyValueSeparator(" ").join(selColMap);
        strBud.append(joiner).append(" from ").append(tbName).append(" ").append(where);

        String sql=strBud.toString();

        return sql;
    }

    String getTbName(Class tbCla){
        TableName tableNameAn = (TableName) tbCla.getAnnotation(TableName.class);
        if(tableNameAn!=null){
            return tableNameAn.value();
        }else{
            return StringHelper.camelToUnderline(tbCla.getName());
        }
    }

    /**
     * 根据属性返回对应的列名
     * 如果列名为空 就说明这个字段不存在对应的数据库列
     * @param fd
     * @return
     */
    String getColName(Field fd){
        TableField tableFieldAn = fd.getAnnotation(TableField.class);
        //  如果为空就直接赋值驼峰命名
        if(tableFieldAn==null){
            return StringHelper.camelToUnderline(fd.getName());
        }

        //  如果字段不存在，就直接返回
        if(!tableFieldAn.exist()){
            return null;
        }

        return tableFieldAn.value();

    }

    public void del(Class tbCla, Serializable id){
        String tbName=getTbName(tbCla);
        String sql="delete from "+tbName+" where id="+id;
        execute(sql);
    }

    public void insert(Object obj){
        if(obj==null){
            throw new RuntimeException("字段为空");
        }
        Class clazz=obj.getClass();
        String tbName=getTbName(clazz);
        Map<String,Object> data=new HashMap<>();
        Field[] allFields = FieldUtils.getAllFields(clazz);
        for (Field fd : allFields) {
            String colName=getColName(fd);
            if(colName==null){
                continue;
            }
            try {
                Object val=FieldUtils.readField(fd,obj,true);
                if(val==null){
                    continue;
                }
                data.put(colName,val);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        insert(tbName,data);
    }

    /**
     * 以 map 和 表名的形式插入数据
     * @param table
     * @param data
     */
    public void insert(String table, Map<String, Object> data) {
        StringBuilder sqlStrBud = new StringBuilder();
        sqlStrBud.append("insert into `").append(table).append("` ");
        sqlStrBud.append("(");
        //  循环设置
        Object[] params = new Object[data.size()];
        AtomicInteger i = new AtomicInteger(0);
        data.forEach((k, v) -> {
            if(k.indexOf("`")!=-1){
                sqlStrBud.append(k);
            }else {
                sqlStrBud.append(" `").append(k).append("`");
            }
            params[i.get()] = v;
            i.addAndGet(1);
            if(i.get()<data.size()){
                sqlStrBud.append(", ");
            }
        });
        sqlStrBud.append(") VALUES (");
        AtomicInteger j = new AtomicInteger(0);
        data.forEach((k, v) -> {
            sqlStrBud.append(" ? ");
            j.addAndGet(1);
            if(j.get()<data.size()){
                sqlStrBud.append(", ");
            }
        });
        sqlStrBud.append(")");
        String sql=sqlStrBud.toString();
        try {
            this.update(sql, params);
        } catch (DataAccessException e) {
            System.out.println("执行报错:"+sql);
            System.out.println(Arrays.toString(params));
            throw e;
        }
    }



}
